﻿using UnityEngine;
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections.Generic;
using System.Xml;

public static class Utils
{
    private const uint FNV32_PRIME = 0x01000193;
    private const uint FNV32_OFFSET_BASIS = 0x811c9dc5;

    public static uint StrHash(string str)
    {
        uint crc32 = FNV32_OFFSET_BASIS;

        for (int i = 0; i < str.Length; i++)
        {
            char c = str[i];
            crc32 *= FNV32_PRIME;
            crc32 ^= c;
        }

        return crc32;
    }

    public static bool Encryption(byte[] buffer, uint pwd)
    {
#if ENCRYPT
        int len = buffer.Length;
        byte[] key = new byte[]
        {
                (byte)((pwd & 0xff000000) >> 24),
                (byte)((pwd & 0x00ff0000) >> 16),
                (byte)((pwd & 0x0000ff00) >> 8),
                (byte)((pwd & 0x000000ff) >> 0)
        };

        for (int i = 0; i < len; i++)
        {
            buffer[i] ^= key[i % 4];
        }
#endif
        return true;
    }

    public static bool Decryption(byte[] buffer, uint pwd)
    {
        return Encryption(buffer, pwd);
    }

    public static bool Encrypted
    {
        get
        {
#if ENCRYPT
            return true;
#else
            return false;
#endif
        }
    }

    public static T GetUIWidget<T>(Transform _tr, string _path) where T : Component
    {
        Transform childTr = _tr.Find(_path);
        if (childTr != null)
        {
            return childTr.GetComponent<T>();
        }

        return null;
    }

    /// <summary>
    /// 判断数组是否相等
    /// </summary>
    public static bool CompareArr<T>(T[] arr1, T[] arr2)
    {
        var q = from a in arr1 join b in arr2 on a equals b select a;

        bool flag = arr1.Length == arr2.Length && q.Count() == arr1.Length;

        return flag;
    }

    /// <summary>
    /// 判断是否为数字
    /// </summary>
    public static bool IsNumeric(string _str)
    {
        if (null == _str || 0 == _str.Length) return false;
        for (int i = 0; i < _str.Length; i++)
        {
            if (!Char.IsNumber(_str[i])) { return false; }
        }
        return true;
    }

    /// <summary>
    /// 时间戳转化为时间
    /// </summary>
    public static DateTime SetTimestamp2DateTime(long _timestamp)
    {
        DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
        DateTime curTime = startTime.AddMilliseconds(_timestamp);
        return curTime;
    }

    /// <summary>
    /// 删除字母和数字
    /// </summary>
    public static string DeleteNumber(string value)
    {
        if (string.IsNullOrEmpty(value)) return null;
        else
        {
            string _str = Regex.Replace(value, @"[0-9]", string.Empty, RegexOptions.IgnoreCase);
            return _str;
        }
    }

    /// <summary>
    /// 删除特殊字符
    /// </summary>
    public static string DeleteChar(string value)
    {
        if (string.IsNullOrEmpty(value)) return null;
        else
        {
            string _str = Regex.Replace(value, "[·`~!@#$%—^&*()=|{}':;',\\[ \\].<>/?~！@#￥……&*（）|{}【】；：‘’，。/* \\- +？、《》\r _ \\p{P}]+", string.Empty, RegexOptions.IgnoreCase);
            return _str;
        }
    }


    /// <summary>
    /// 限制文字长度
    /// </summary>
    /// <param name="value">输入文字</param>
    /// <param name="startIndex">文字起始位置</param>
    /// <param name="length">限制长度</param>
    /// <returns></returns>
    public static string LimitStringLength(string value, int startIndex, int length)
    {
        if (string.IsNullOrEmpty(value))
            return null;
        else
        {
            byte[] subbyte = System.Text.Encoding.Default.GetBytes(value);
            if (length > value.Length)
            {
                string sub = System.Text.Encoding.Default.GetString(subbyte);
                return sub;
            }
            else
            {
                string sub = System.Text.Encoding.Default.GetString(subbyte, startIndex, length);
                return sub;
            }
        }
    }

    public static string SubString(string value, int startIdx, int length)
    {
        string str = DeleteNumber(value);
        string _str = DeleteChar(str);
        string __str = LimitStringLength(_str, startIdx, length);
        return __str;
    }

    public enum RenderingMode
    {
        Opaque,
        Cutout,
        Fade,
        Transparent,
    }

    /// <summary>
    /// 转换透明度
    /// </summary>
    /// <param name="renderQueue"></param>
    /// <returns></returns>
    public static RenderingMode SwitchRenderQueue(int renderQueue)
    { 
        if(renderQueue < 2450)
        {
            return RenderingMode.Opaque;
        }
        else if (renderQueue == 2450)
        {
            return RenderingMode.Cutout;
        }
        else
        {
            return RenderingMode.Fade;
        }
    }

    /// <summary>
    /// 设置材质渲染模式
    /// </summary>
    /// <param name="material"></param>
    /// <param name="renderingMode"></param>
    public static void SetMaterialRenderingMode(Material material, RenderingMode renderingMode)
    {
        switch (renderingMode)
        {
            case RenderingMode.Opaque:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case RenderingMode.Cutout:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case RenderingMode.Fade:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case RenderingMode.Transparent:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }

    /// <summary>
    /// 设置材质渲染模式
    /// </summary>
    /// <param name="material"></param>
    /// <param name="renderingMode"></param>
    public static void SetMRTKStandardShaderMode(Material material, RenderingMode renderingMode)
    {
        switch (renderingMode)
        {
            case RenderingMode.Opaque:
                material.SetFloat("_Mode", 0);
                material.SetFloat("_SrcBlend", 1);
                material.SetFloat("_DstBlend", 0);
                material.SetFloat("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case RenderingMode.Cutout:
                material.SetFloat("_Mode", 1);
                material.SetFloat("_SrcBlend", 1);
                material.SetFloat("_DstBlend", 0);
                material.SetFloat("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case RenderingMode.Fade:
                material.SetFloat("_Mode", 2);
                material.SetFloat("_SrcBlend", 5);
                material.SetFloat("_DstBlend", 10);
                material.SetFloat("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case RenderingMode.Transparent:
                material.SetFloat("_Mode", 3);
                material.SetFloat("_SrcBlend", 1);
                material.SetFloat("_DstBlend", 10);
                material.SetFloat("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }

    public static void CreateFile(byte[] bytes, string path)
    {
        FileInfo file = new FileInfo(path);
        using (Stream stream = file.Create())
        {
            stream.Write(bytes, 0, bytes.Length);
        }
    }

    public static Dictionary<string, string> ReadMD5XmlFile(string fileName)
    {
        if (!File.Exists(fileName))
            return null;

        Dictionary<string, string> DicMD5 = new Dictionary<string, string>();
        XmlDocument XmlDoc = new XmlDocument();
        XmlDoc.Load(fileName);
        XmlElement XmlRoot = XmlDoc.DocumentElement;

        foreach (XmlNode node in XmlRoot.ChildNodes)
        {
            if (!(node is XmlElement))
                continue;

            string file = (node as XmlElement).GetAttribute("FileName");
            string md5 = (node as XmlElement).GetAttribute("MD5");

            if (!DicMD5.ContainsKey(file))
            {
                DicMD5.Add(file, md5);
            }
            else
            {
                Debug.LogError(fileName + " 存在重复文件名");
            }
        }

        return DicMD5;
    }

    /// <summary>
    /// 获取某个gameobject
    /// </summary>
    public static Transform GetGameObject(string child, Transform target)
    {
        Transform trans = target.Find(child);
        if (!trans)
        {
            trans = new GameObject(child).transform;
            trans.SetParent(target);
            trans.localPosition = Vector3.zero;
            trans.localScale = Vector3.one;
            trans.localEulerAngles = Vector3.zero;
        }
        return trans;
    }
}
